WebRTC研究:rrt 时间计算 之 发送 SR / RR 包

您所在的位置:网站首页 android 获取当前时间戳 WebRTC研究:rrt 时间计算 之 发送 SR / RR 包

WebRTC研究:rrt 时间计算 之 发送 SR / RR 包

2023-04-08 18:54| 来源: 网络整理| 查看: 265

一、ModuleRtpRtcpImpl::Process() 会定时处理 SR/RR 包发送、bitrate、rrt 等事宜,处理时间间隔为 5 ms:

int64_t ModuleRtpRtcpImpl::TimeUntilNextProcess() { /* last_process_time_:上次调用 Process() 的开始时间 理论上是,在本次调用 Process() 之后,需等待 5ms,然后再次执行 Process() 但是由于调用 Process() 本身存在耗时,因此实际等待时间需要减掉这部分耗时 */ const int64_t now = clock_->TimeInMilliseconds(); const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5; return kRtpRtcpMaxIdleTimeProcessMs - (now - last_process_time_); } 二、发送 SR / RR 包

对于 audio,发送 SR / RR 包的时间间隔为 [1/2 * 5000, 3/2 * 5000] ms 之间的一个随机数:

void ModuleRtpRtcpImpl::Process() { ... ... ... /* 判断发送 RTP 包的时间是否到达 */ if (rtcp_sender_.TimeToSendRTCPReport()) { /* 获取 最近收到的 SR 包中所携带的 NTP 时间戳、收到 SR 包时本地时间戳等信息 */ RTCPSender::FeedbackState state = GetFeedbackState(); // Prevent sending streams to send SR before any media has been sent. if (!rtcp_sender_.Sending() || state.packets_sent > 0) rtcp_sender_.SendRTCP(state, kRtcpReport); /* 发送RTP包 并计算下一次发送 RTP包的时间 */ } ... ... ... }

相关学习资料推荐,点击下方链接免费报名,先码住不迷路~】

音视频免费学习地址:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发

【免费分享】音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击788280672加群免费领取~

三、获取最近收到的 SR 包中所携带的 NTP 时间戳、收到 SR 包时本地时间戳等信息:

RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() { ... ... ... /* remote_sr:最近收到的 SR 包中所携带的 NTP 时间戳的中间32位 last_rr_ntp_secs / last_rr_ntp_frac:最近收到 SR 包时的当前时间戳 */ LastReceivedNTP(&state.last_rr_ntp_secs, &state.last_rr_ntp_frac, &state.remote_sr); ... ... ... } bool ModuleRtpRtcpImpl::LastReceivedNTP( uint32_t* rtcp_arrival_time_secs, // When we got the last report. uint32_t* rtcp_arrival_time_frac, uint32_t* remote_sr) const { // Remote SR: NTP inside the last received (mid 16 bits from sec and frac). uint32_t ntp_secs = 0; uint32_t ntp_frac = 0; if (!rtcp_receiver_.NTP(&ntp_secs, &ntp_frac, rtcp_arrival_time_secs, rtcp_arrival_time_frac, NULL)) { return false; } *remote_sr = ((ntp_secs & 0x0000ffff) > 16); return true; }

_remoteSenderInfo.NTPseconds 与 _remoteSenderInfo.NTPfraction:最近收到的 SR 包中所携带的 NTP 时间戳。

_lastReceivedSRNTPfrac 与 _lastReceivedSRNTPsecs:最近收到 SR 包时的本地时间戳。

具体来源,参考前一篇文章:WebRTC研究:rrt 时间计算 之 接收 SR 包

// TODO(pbos): Make this fail when we haven't received NTP. bool RTCPReceiver::NTP(uint32_t* ReceivedNTPsecs, uint32_t* ReceivedNTPfrac, uint32_t* RTCPArrivalTimeSecs, uint32_t* RTCPArrivalTimeFrac, uint32_t* rtcp_timestamp) const { rtc::CritScope lock(&_criticalSectionRTCPReceiver); if(ReceivedNTPsecs) { *ReceivedNTPsecs = _remoteSenderInfo.NTPseconds; // SR 包所携带 NTP 时间戳 } if(ReceivedNTPfrac) { *ReceivedNTPfrac = _remoteSenderInfo.NTPfraction; } if(RTCPArrivalTimeFrac) { *RTCPArrivalTimeFrac = _lastReceivedSRNTPfrac; // 接收到 SR 包时的当前 NTP 时间戳 } if(RTCPArrivalTimeSecs) { *RTCPArrivalTimeSecs = _lastReceivedSRNTPsecs; } if (rtcp_timestamp) { *rtcp_timestamp = _remoteSenderInfo.RTPtimeStamp; } return true; }

四、PrepareReport() 会根据字段 sending_(是否发送端)的值,判定发送 SR 还是 RR 包:

void RTCPSender::PrepareReport(const std::set& packetTypes, const FeedbackState& feedback_state) { ... ... ... /* 根据 sending_(是否发送端)判定发送 SR 或 RR 包 SetFlag():将 flag:kRtcpSr 或 kRtcpRr 存入 集合 report_flags_,节点内部字段:is_volatile 的值设置为 true。 */ if (generate_report) SetFlag(sending_ ? kRtcpSr : kRtcpRr, true); ... ... ... /* 计算下次发送 RTCP 的时间,每次时间间隔不一, 对于 audio,时间间隔是 [1/2 * 5000, 3/2 * 5000] ms之间的一个随机数 */ uint32_t timeToNext = random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2); next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext; /* AddReportBlock()会设置两个关键值: last_sr_:SR 包中 NTP 时间戳的中间32位 delay_since_last_sr_:从收到 SR包 到发送 RR包 之间的延时 */ if (receive_statistics_) { StatisticianMap statisticians = receive_statistics_->GetActiveStatisticians(); RTC_DCHECK(report_blocks_.empty()); for (auto& it : statisticians) { AddReportBlock(feedback_state, it.first, it.second); } } ... ... ... }

五、设置 last_sr_(SR 包中 NTP 时间戳的中间32位)与 delay_since_last_sr_(从 接到SR包 到 发送RR包 之间的延时):

bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state, uint32_t ssrc, StreamStatistician* statistician) { ... ... ... rtcp::ReportBlock* block = &report_blocks_[ssrc]; /* 设置 last_sr_,即为 SR 包中 NTP 时间戳的中间32位 */ block->WithLastSr(feedback_state.remote_sr); // Delay since last received report. if ((feedback_state.last_rr_ntp_secs != 0) || (feedback_state.last_rr_ntp_frac != 0)) { // Get the 16 lowest bits of seconds and the 16 highest bits of fractions. uint32_t now = ntp_secs & 0x0000FFFF; now 16; uint32_t receiveTime = feedback_state.last_rr_ntp_secs & 0x0000FFFF; receiveTime 16; /* 设置 delay_since_last_sr_,即为 从接到SR包 到发送RR包 之间的延时 */ block->WithDelayLastSr(now - receiveTime); } return true; ... ... ... }

六、根据发送 SR 包还是RR 包,调用不同的包封装函数:

int32_t RTCPSender::SendCompoundRTCP( const FeedbackState& feedback_state, const std::set& packet_types, int32_t nack_size, const uint16_t* nack_list, bool repeat, uint64_t pictureID) { ... ... ... // 获取当前 NTP 时间戳 uint32_t ntp_sec; uint32_t ntp_frac; clock_->CurrentNtp(ntp_sec, ntp_frac); RtcpContext context(feedback_state, nack_size, nack_list, repeat, pictureID, ntp_sec, ntp_frac); // 判断是发送 SR 包还是RR 包,并设置 last_sr_ 与 delay_since_last_sr_ PrepareReport(packet_types, feedback_state); std::unique_ptr packet_bye; // 封装包 auto it = report_flags_.begin(); while (it != report_flags_.end()) { auto builder_it = builders_.find(it->type); RTC_DCHECK(builder_it != builders_.end()); if (it->is_volatile) { report_flags_.erase(it++); } else { ++it; } /* 根据 flag 调用对应的包封装函数: kRtcpSr:RTCPSender::BuildSR kRtcpRr:RTCPSender::BuildRR */ BuilderFunc func = builder_it->second; std::unique_ptr packet = (this->*func)(context); ... ... ... } // 发送包 size_t bytes_sent = container.SendPackets(max_payload_length_); return bytes_sent == 0 ? -1 : 0; }

七、封装 SR 包:

std::unique_ptr RTCPSender::BuildSR(const RtcpContext& ctx) { ... ... ... /* 封装当前 NTP 时间戳 */ report->WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_)); report->WithRtpTimestamp(rtp_timestamp); ... ... ... } 八、封装 RR 包:

直接使用 map 对象 report_blocks_ 构造包:

std::unique_ptr RTCPSender::BuildRR(const RtcpContext& ctx) { rtcp::ReceiverReport* report = new rtcp::ReceiverReport(); report->From(ssrc_); for (auto it : report_blocks_) report->WithReportBlock(it.second); report_blocks_.clear(); return std::unique_ptr(report); }

原文 WebRTC研究:rrt 时间计算 之 发送 SR / RR 包



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3